/*
 * balance.h
 */

#define _GNU_SOURCE 1
#include <sched.h> //for binding process to processor

#include <stdio.h>
#include <strings.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <signal.h>
#include <stdlib.h>
#include <sysexits.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/mman.h>
#include <pthread.h>
#include <sys/un.h>

#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>	/* for TCP_NODELAY definition */

#define MAX_MESSAGE_SIZE 	1024
#define FILE_NAME_LEN 	    108
#define MAX_CHANNELS 		64	     /* max channels in group          */
#define MAX_GROUPS   		16     	/* max groups                     */
#define DEFAULT_SELECT_TIMEOUT  0 	/* timeout for select             */
#define SOCKET_BUFFER_SIZE  10*MAX_MESSAGE_SIZE
#define SIZE_OF_ID INET_ADDRSTRLEN
#define BALANCE_QUEUE_LENGTH SOMAXCONN

enum  channel_status_t {CHANNEL_DISABLED = 0, CHANNEL_ENABLED = 1};
enum  boolean_t {FALSE = 0 , TRUE = 1};

typedef struct {
	enum channel_status_t status;
	char channel_path[FILE_NAME_LEN]; /*worker's unix socket path, after initialization is read-only */
	int c; /* current # of connections           */
	int tc; /* total # of connections             */
	int maxc; /* max # of connections, 0 = no limit, after initialization is read-only */
	unsigned long bsent; /* bytes sent                         */
	unsigned long breceived; /* bytes received                     */
} CHANNEL;

#define GROUP_RR	0	/* Round Robin            */
#define GROUP_HASH	1	/* Hash on Client Address */

typedef struct {
	int nchannels;/* number of channels in group, after initialization is read-only   */
	int current;  /* current channel index in group            */
	int type;     /* either GROUP_RR or GROUP_HASH, after initialization is read-only */
	CHANNEL channels[MAX_CHANNELS];
} GROUP;

typedef struct {
	int fc;               /*number of failed connections*/
	int pid;              /*process id, after init is read-only*/
	int ngroups;          /*number of defined groups, after init is read-only*/
	GROUP groups[MAX_GROUPS];
} COMMON;

/*
 * Macros to access various elements of struct GROUP and struct CHANNEL
 * within COMMON array
 *
 * a       pointer to variable of type COMMON
 * g       group index
 * i       channel index
 */
#define cmn_fc(a)                ((a)->fc)
#define cmn_ngroups(a)         ((a)->ngroups)
#define cmn_group(a,g)       	 ((a)->groups[(g)])
#define grp_nchannels(a,g) 	     (cmn_group((a),(g)).nchannels)
#define grp_current(a,g)    	 (cmn_group((a),(g)).current)
#define grp_type(a,g)  	 	     (cmn_group((a),(g)).type)
#define grp_channel(a,g,i)  	 (cmn_group((a),(g)).channels[(i)])
#define chn_status(a,g,i)   	 (grp_channel((a),(g),(i)).status)
#define chn_path(a,g,i)	     (grp_channel((a),(g),(i)).channel_path)
#define chn_c(a,g,i)	    	 (grp_channel((a),(g),(i)).c)
#define chn_tc(a,g,i)		     (grp_channel((a),(g),(i)).tc)
#define chn_maxc(a,g,i)		     (grp_channel((a),(g),(i)).maxc)
#define chn_bsent(a,g,i)	     (grp_channel((a),(g),(i)).bsent)
#define chn_breceived(a,g,i)	 (grp_channel((a),(g),(i)).breceived)

typedef struct thread_params {
	int clientfd;
	int group_index;
	int channel_index;
	struct in_addr client_address;
	enum boolean_t is_one_worker;
} thread_params_t;
